//
//  ACNavigationAnimationManager.swift
//  ACFrameworkSwift
//
//  Created by fisherman on 2021/12/22.
//

import Foundation

/**
 * push、pop 转场统一管理
 *
 * 示例：DemoViewController
 * - 定义  let customNavigationAnimationMgr = ACNavigationAnimationManager()
 * - 关联代理 self.navigationController?.delegate = customNavigationAnimationMgr
 */
public class ACNavigationAnimationManager: NSObject {
    
    /// 动画体
    private var navigationAnimator = ACNavigationAnimator()
    /// 手势交互体
    private var navigationInteraction = ACNavigationInteraction()
    
}

// MARK: - UINavigationControllerDelegate

extension ACNavigationAnimationManager: UINavigationControllerDelegate {
    
    public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        navigationAnimator.isPop = operation == .pop
        if operation == .push {
            navigationInteraction.attachToViewController(viewController: toVC)
        }
        return navigationAnimator
    }
    
    public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return navigationInteraction.transitionInProgress ? navigationInteraction : nil
    }
}


// MARK: - UIViewControllerAnimatedTransitioning

/// push or pop  自定义动画实现
class ACNavigationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    var isPop: Bool = false
        
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        guard let toViewController = transitionContext.viewController(forKey: .to),
              let fromViewController = transitionContext.viewController(forKey: .from),
              let toView = toViewController.view,
              let fromView = fromViewController.view else { return }
        
        let targetView: UIView
        let finishedAlpha: CGFloat
        if isPop {
            targetView = fromView
            finishedAlpha = 0.0
            containerView.insertSubview(toView, belowSubview: fromView)
        }else {
            containerView.addSubview(toView)
            toView.alpha = 0.0
            targetView = toView
            finishedAlpha = 1.0
        }
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
            targetView.alpha = finishedAlpha
        } completion: { finished in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

// MARK: - UIViewControllerInteractiveTransitioning

/**
 * 对自定义的 push、pop 动画，增加侧滑手势返回（默认不存在手势返回）
 *  - 以 200 为边界
 */
class ACNavigationInteraction: UIPercentDrivenInteractiveTransition {
    private var navigationController: UINavigationController!
    var shouldCompleteTransition = false
    var transitionInProgress = false
    var completionSeed: CGFloat {
        return 1 - percentComplete
    }
        
    func attachToViewController(viewController: UIViewController) {
        navigationController = viewController.navigationController
        setupGestureRecognizer(view: viewController.view)
    }
        
    private func setupGestureRecognizer(view: UIView) {
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:))))
    }
    
    @objc
    func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
        let viewTranslation = gestureRecognizer.translation(in: gestureRecognizer.view!.superview!)
        switch gestureRecognizer.state {
        case .began:
            transitionInProgress = true
            navigationController.popViewController(animated: true)
        case .changed:
            let const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))
            shouldCompleteTransition = const > 0.5
            update(const)
        case .cancelled, .ended:
            transitionInProgress = false
            if !shouldCompleteTransition || gestureRecognizer.state == .cancelled {
                cancel()
            } else {
                finish()
            }
        default:
            print("Swift switch must be exhaustive, thus the default")
        }
    }
}
